package ixOrm

import (
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	ixRedis "gitee.com/ixgo/redis"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// Client 数据库客户端
type Client struct {
	db          *gorm.DB
	config      *Config
	cache       CacheInterface // 默认缓存（向后兼容）
	redisCache  CacheInterface // Redis缓存实例
	memoryCache CacheInterface // 内存缓存实例
	mutex       sync.RWMutex
}

// NewClient 创建数据库客户端
func NewClient(config *Config, options ...ConfigOption) (*Client, error) {
	// 应用配置选项
	for _, option := range options {
		option(config)
	}

	// 验证配置
	if err := config.Validate(); err != nil {
		return nil, fmt.Errorf("配置验证失败: %w", err)
	}

	// 构建DSN
	var dsn string
	if config.SqlConn != "" {
		// 如果设置了 SqlConn，直接使用
		dsn = config.SqlConn
	} else {
		// 否则根据其他参数构建DSN
		dsn = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&collation=%s&parseTime=%t&loc=%s",
			config.Username,
			config.Password,
			config.Host,
			config.Port,
			config.Database,
			config.Charset,
			config.Collation,
			config.ParseTime,
			config.Loc,
		)
	}

	// 创建GORM配置
	var gormConfig *gorm.Config
	if config.GormConfig != nil {
		// 使用自定义GORM配置
		gormConfig = config.GormConfig
	} else {
		// 根据debug模式设置日志级别
		logLevel := logger.LogLevel(config.LogLevel)
		if config.DebugMode {
			logLevel = logger.Info // debug模式下显示所有SQL
		}

		// 使用默认GORM配置
		gormConfig = &gorm.Config{
			Logger: logger.New(
				log.New(os.Stdout, "\r\n", log.LstdFlags),
				logger.Config{
					SlowThreshold: config.SlowThreshold,
					LogLevel:      logLevel,
					Colorful:      true,
				},
			),
		}
	}

	// 打开数据库连接
	db, err := gorm.Open(mysql.Open(dsn), gormConfig)
	if err != nil {
		return nil, fmt.Errorf("连接数据库失败: %w", err)
	}

	// 配置连接池
	sqlDB, err := db.DB()
	if err != nil {
		return nil, fmt.Errorf("获取SQL DB失败: %w", err)
	}

	sqlDB.SetMaxOpenConns(config.MaxOpenConns)
	sqlDB.SetMaxIdleConns(config.MaxIdleConns)
	sqlDB.SetConnMaxLifetime(config.ConnMaxLifetime)

	// 创建客户端
	client := &Client{
		db:     db,
		config: config.Clone(),
		cache:  NewNullCache(), // 默认使用空缓存
	}

	// 初始化缓存（如果启用）
	if config.EnableCache {
		if err := client.initCache(); err != nil {
			return nil, fmt.Errorf("初始化缓存失败: %w", err)
		}
	}

	return client, nil
}

// initCache 初始化缓存（根据配置类型）
func (c *Client) initCache() error {
	// 初始化内存缓存（总是可用）
	if err := c.initMemoryCache(); err != nil {
		return fmt.Errorf("初始化内存缓存失败: %w", err)
	}

	// 初始化Redis缓存（如果配置了Redis）
	if c.config.RedisConfig != nil {
		if err := c.initRedisCache(); err != nil {
			// Redis初始化失败时，继续使用内存缓存
			fmt.Printf("[ixOrm] 警告: Redis缓存初始化失败，将使用内存缓存: %v\n", err)
		} else {
			fmt.Printf("[ixOrm] 信息: Redis缓存初始化成功\n")
		}
	}

	// 设置默认缓存
	switch c.config.CacheType {
	case CacheTypeRedis:
		if c.redisCache != nil {
			c.cache = c.redisCache
		} else {
			c.cache = c.memoryCache // Redis不可用时降级到内存缓存
		}
	case CacheTypeMemory:
		c.cache = c.memoryCache
	case CacheTypeNone:
		c.cache = NewNullCache()
	default:
		// 默认使用Redis缓存，如果Redis不可用则使用内存缓存
		if c.redisCache != nil {
			c.cache = c.redisCache
		} else {
			c.cache = c.memoryCache
		}
	}

	return nil
}

// initRedisCache 初始化Redis缓存
func (c *Client) initRedisCache() error {
	if c.config.RedisConfig == nil {
		return fmt.Errorf("Redis配置未设置")
	}

	var redisClient *ixRedis.Client
	var err error

	// 暂时忽略 Conn 参数，使用分离参数
	redisConfig := &ixRedis.Config{
		Host:     c.config.RedisConfig.Host,
		Port:     c.config.RedisConfig.Port,
		Password: c.config.RedisConfig.Password,
		DB:       c.config.RedisConfig.Database,
	}
	redisClient, err = ixRedis.NewClient(redisConfig)

	if err != nil {
		return fmt.Errorf("创建Redis客户端失败: %w", err)
	}

	// 使用Redis专用的TTL，如果没有设置则使用默认TTL
	redisTTL := c.config.RedisCacheTTL
	if redisTTL == 0 {
		redisTTL = c.config.CacheTTL
	}

	// 使用配置的前缀，如果没有设置则使用默认前缀
	redisPrefix := c.config.RedisConfig.Prefix
	if redisPrefix == "" {
		redisPrefix = "ixorm:"
	}

	c.redisCache = NewRedisCache(redisClient, redisPrefix, redisTTL)
	return nil
}

// initMemoryCache 初始化内存缓存
func (c *Client) initMemoryCache() error {
	// 使用内存缓存专用的TTL，如果没有设置则使用默认TTL
	memoryTTL := c.config.MemoryCacheTTL
	if memoryTTL == 0 {
		memoryTTL = c.config.CacheTTL
	}
	c.memoryCache = NewMemoryCache("ixorm:", memoryTTL)

	// 设置调试模式
	if c.config.CacheDebugMode {
		if memoryCache, ok := c.memoryCache.(*MemoryCache); ok {
			memoryCache.SetDebugMode(true)
		}
	}

	return nil
}

// DB 获取GORM实例
func (c *Client) DB() *gorm.DB {
	if c == nil {
		return nil
	}
	return c.db
}

// SetCache 设置缓存实例
func (c *Client) SetCache(cache CacheInterface) {
	c.mutex.Lock()
	c.cache = cache
	c.mutex.Unlock()
}

// GetCacheByType 根据类型获取缓存实例
func (c *Client) GetCacheByType(cacheType CacheType) CacheInterface {
	if c == nil || !c.config.EnableCache {
		return NewNullCache()
	}

	switch cacheType {
	case CacheTypeRedis:
		if c.redisCache != nil {
			return c.redisCache
		}
		// Redis不可用时，降级到内存缓存
		if c.memoryCache != nil {
			return c.memoryCache
		}
		return NewNullCache()
	case CacheTypeMemory:
		if c.memoryCache != nil {
			return c.memoryCache
		}
		// 如果内存缓存不存在，创建一个临时的
		memoryTTL := c.config.MemoryCacheTTL
		if memoryTTL == 0 {
			memoryTTL = c.config.CacheTTL
		}
		return NewMemoryCache("ixorm:", memoryTTL)
	case CacheTypeNone:
		return NewNullCache()
	default:
		// 默认返回当前设置的缓存
		return c.cache
	}
}

// GetCache 获取缓存实例（无锁优化版本）
func (c *Client) GetCache() CacheInterface {
	// 由于cache在初始化后很少变更，使用原子操作或直接读取
	// 这里简化为直接读取，因为在Go中接口的读取是原子的
	return c.cache
}

// GetRedisCache 获取Redis缓存实例
func (c *Client) GetRedisCache() CacheInterface {
	if c == nil {
		return NewNullCache()
	}
	return c.redisCache
}

// GetMemoryCache 获取内存缓存实例
func (c *Client) GetMemoryCache() CacheInterface {
	if c == nil {
		return NewNullCache()
	}
	return c.memoryCache
}

// HasRedisCache 检查是否配置了Redis缓存
func (c *Client) HasRedisCache() bool {
	return c != nil && c.redisCache != nil
}

// HasMemoryCache 检查是否配置了内存缓存
func (c *Client) HasMemoryCache() bool {
	return c != nil && c.memoryCache != nil
}

// SetDefaultCacheType 设置默认缓存类型
func (c *Client) SetDefaultCacheType(cacheType CacheType) {
	if c == nil {
		return
	}

	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.config.CacheType = cacheType

	// 更新默认缓存
	switch cacheType {
	case CacheTypeRedis:
		if c.redisCache != nil {
			c.cache = c.redisCache
		} else if c.memoryCache != nil {
			c.cache = c.memoryCache // Redis不可用时降级到内存缓存
		}
	case CacheTypeMemory:
		if c.memoryCache != nil {
			c.cache = c.memoryCache
		}
	case CacheTypeNone:
		c.cache = NewNullCache()
	}
}

// Close 关闭数据库连接
func (c *Client) Close() error {
	if c == nil || c.db == nil {
		return nil
	}
	sqlDB, err := c.db.DB()
	if err != nil {
		return err
	}
	return sqlDB.Close()
}

// Ping 检查数据库连接
func (c *Client) Ping() error {
	if c == nil || c.db == nil {
		return fmt.Errorf("数据库连接未初始化")
	}
	sqlDB, err := c.db.DB()
	if err != nil {
		return err
	}
	return sqlDB.Ping()
}

// Table 指定表名进行操作
func (c *Client) Table(tableName string) *TableOperator {
	if c == nil || c.db == nil {
		return &TableOperator{
			client:    c,
			tableName: tableName,
			db:        nil,
		}
	}
	return &TableOperator{
		client:    c,
		tableName: tableName,
		db:        c.db.Table(tableName),
	}
}

// TableOperator 表操作器
type TableOperator struct {
	client       *Client
	tableName    string
	db           *gorm.DB
	useCache     bool
	cacheKey     string
	cacheTTL     time.Duration
	baseCacheKey string // 缓存基础键，避免重复计算
}

// WithCache 启用缓存
func (t *TableOperator) WithCache(args ...interface{}) *TableOperator {
	if len(args) == 0 {
		return t
	}

	// 解析第一个参数
	switch v := args[0].(type) {
	case bool:
		// WithCache(true) 或 WithCache(false)
		t.useCache = v
		if v {
			t.cacheKey = "" // 空字符串表示自动生成
		}
	case string:
		// WithCache("key") 或 WithCache("key", ttl)
		t.useCache = true
		t.cacheKey = v
	default:
		// 不支持的类型，不启用缓存
		return t
	}

	// 解析第二个参数（过期时间）
	if len(args) > 1 {
		if ttl, ok := args[1].(time.Duration); ok {
			t.cacheTTL = ttl
		}
	} else {
		// 使用默认过期时间，根据当前缓存类型选择合适的TTL
		if t.client != nil && t.client.config != nil {
			switch t.client.config.CacheType {
			case CacheTypeRedis:
				if t.client.config.RedisCacheTTL > 0 {
					t.cacheTTL = t.client.config.RedisCacheTTL
				} else {
					t.cacheTTL = t.client.config.CacheTTL
				}
			case CacheTypeMemory:
				if t.client.config.MemoryCacheTTL > 0 {
					t.cacheTTL = t.client.config.MemoryCacheTTL
				} else {
					t.cacheTTL = t.client.config.CacheTTL
				}
			default:
				// 默认情况下，如果有Redis配置则使用Redis TTL，否则使用通用TTL
				if t.client.config.RedisCacheTTL > 0 {
					t.cacheTTL = t.client.config.RedisCacheTTL
				} else {
					t.cacheTTL = t.client.config.CacheTTL
				}
			}
		} else {
			t.cacheTTL = time.Minute * 5 // 兜底默认值
		}
	}

	// 如果客户端没有真正的缓存但启用了缓存，尝试初始化
	if t.useCache && t.client != nil && t.client.config != nil && t.client.config.EnableCache {
		if _, isNullCache := t.client.cache.(*NullCache); isNullCache {
			// 尝试初始化缓存
			if err := t.client.initCache(); err == nil {
				// 缓存初始化成功
			}
		}
	}

	return t
}

// autoCreateTable 自动创建表
func (t *TableOperator) autoCreateTable(model interface{}) error {
	if t == nil || t.client == nil || t.client.db == nil {
		return fmt.Errorf("数据库连接未初始化")
	}
	return t.client.db.Table(t.tableName).AutoMigrate(model)
}

// isTableNotExistError 检查是否是表不存在错误
func (t *TableOperator) isTableNotExistError(err error) bool {
	if err == nil {
		return false
	}
	errStr := strings.ToLower(err.Error())

	// 调试信息：打印错误信息
	if t.client != nil && t.client.config != nil && t.client.config.DebugMode {
		fmt.Printf("[ixOrm-DEBUG] 检查表不存在错误: %s\n", err.Error())
	}

	// 检查各种可能的表不存在错误信息
	tableNotExistPatterns := []string{
		"doesn't exist",
		"not exist",
		"unknown table",
		"table doesn't exist",
		"table not exist",
		"no such table",
		"table '",
		"doesn't exist",
		"不存在",
		"表不存在",
		"unknown table",
		"table not found",
		"relation does not exist",      // PostgreSQL
		"object does not exist",        // Oracle
		"table or view does not exist", // Oracle
	}

	// 检查是否包含表相关的关键词
	hasTableKeyword := strings.Contains(errStr, "table") ||
		strings.Contains(errStr, "relation") ||
		strings.Contains(errStr, "object") ||
		strings.Contains(errStr, "view")

	if !hasTableKeyword {
		return false
	}

	// 检查是否匹配任何表不存在的模式
	for _, pattern := range tableNotExistPatterns {
		if strings.Contains(errStr, pattern) {
			if t.client != nil && t.client.config != nil && t.client.config.DebugMode {
				fmt.Printf("[ixOrm-DEBUG] 匹配到表不存在模式: %s\n", pattern)
			}
			return true
		}
	}

	return false
}

// generateCacheKey 生成缓存键（优化版本）
func (t *TableOperator) generateCacheKey(operation string, params ...interface{}) string {
	if t.cacheKey != "" {
		return t.cacheKey
	}

	// 缓存基础键部分，避免重复计算
	if t.baseCacheKey == "" {
		t.baseCacheKey = t.buildBaseCacheKey()
	}

	// 构建完整缓存键
	key := t.baseCacheKey + ":" + operation
	if len(params) > 0 {
		// 转换参数为简洁格式
		paramStr := t.formatCacheParams(params...)
		if paramStr != "" {
			key += ":" + paramStr
		}
	}
	return key
}

// buildBaseCacheKey 构建基础缓存键（实例名:数据库名:表名）
func (t *TableOperator) buildBaseCacheKey() string {
	var instanceName, databaseName string

	// 获取实例名（从管理器中查找）
	if t.client != nil {
		manager := GetManager()
		instanceName = manager.GetInstanceName(t.client)
		// 如果未找到实例名，使用数据库名作为实例名
		if instanceName == "unknown" && t.client.config != nil {
			instanceName = t.client.config.Database
		}
	}

	// 获取数据库名
	if t.client != nil && t.client.config != nil {
		if t.client.config.SqlConn != "" {
			// 从 SqlConn 中提取数据库名（简化处理）
			databaseName = "fromconn"
		} else {
			databaseName = t.client.config.Database
		}
	}

	return fmt.Sprintf("ixorm:%s:%s:%s", instanceName, databaseName, t.tableName)
}

// formatCacheParams 格式化缓存参数（优化版本）
func (t *TableOperator) formatCacheParams(params ...interface{}) string {
	if len(params) == 0 {
		return ""
	}

	// 预估容量，减少内存分配
	var builder strings.Builder
	// 根据参数数量动态预估容量
	estimatedSize := len(params) * 16 // 每个参数平均16字节
	if estimatedSize < 64 {
		estimatedSize = 64
	}
	builder.Grow(estimatedSize)

	first := true
	for _, param := range params {
		if !first {
			builder.WriteByte('_')
		}
		first = false

		switch v := param.(type) {
		case map[string]interface{}:
			// 处理条件map - 需要排序以确保键的一致性
			// 提取所有键并排序
			keys := make([]string, 0, len(v))
			for field := range v {
				keys = append(keys, field)
			}

			// 对键进行排序，确保顺序一致
			for i := 0; i < len(keys)-1; i++ {
				for j := i + 1; j < len(keys); j++ {
					if keys[i] > keys[j] {
						keys[i], keys[j] = keys[j], keys[i]
					}
				}
			}

			// 按排序后的键顺序构建字符串
			mapFirst := true
			for _, field := range keys {
				if !mapFirst {
					builder.WriteByte('_')
				}
				mapFirst = false
				builder.WriteString(field)
				builder.WriteByte('_')
				builder.WriteString(formatValue(v[field]))
			}
		case []string:
			// 处理字符串切片（如OrderBy）
			if len(v) > 0 {
				builder.WriteString(strings.Join(v, "_"))
			}
		case int:
			// 处理数字（如Limit, Offset）
			if v > 0 {
				builder.WriteString(formatInt(v))
			}
		case string:
			// 处理字符串
			if v != "" {
				builder.WriteString(v)
			}
		default:
			// 其他类型转为字符串
			if v != nil {
				str := formatValue(v)
				if str != "" {
					builder.WriteString(str)
				}
			}
		}
	}

	return builder.String()
}

// formatValue 格式化值（避免使用fmt.Sprintf）
func formatValue(v interface{}) string {
	switch val := v.(type) {
	case string:
		return val
	case int:
		return formatInt(val)
	case int64:
		return formatInt64(val)
	case float64:
		return formatFloat64(val)
	case bool:
		if val {
			return "true"
		}
		return "false"
	default:
		return fmt.Sprintf("%v", val)
	}
}

// formatInt 格式化整数（避免fmt.Sprintf）
func formatInt(i int) string {
	if i == 0 {
		return "0"
	}
	return fmt.Sprintf("%d", i)
}

// formatInt64 格式化int64
func formatInt64(i int64) string {
	if i == 0 {
		return "0"
	}
	return fmt.Sprintf("%d", i)
}

// formatFloat64 格式化float64
func formatFloat64(f float64) string {
	if f == 0 {
		return "0"
	}
	return fmt.Sprintf("%.2f", f)
}

// ClearCache 清除当前表的所有缓存
func (t *TableOperator) ClearCache() error {
	if t == nil || t.client == nil || t.client.cache == nil {
		return nil
	}

	// 如果有自定义缓存键，直接删除它
	if t.cacheKey != "" {
		t.client.cache.Del(t.cacheKey)
	}

	// 清除自动生成的缓存键：*:表名:*
	pattern1 := fmt.Sprintf("*:%s:*", t.tableName)
	t.client.cache.DelPattern(pattern1)

	// 清除可能的其他自定义缓存键：*表名*
	pattern2 := fmt.Sprintf("*%s*", t.tableName)
	t.client.cache.DelPattern(pattern2)

	return nil
}

// ClearRelatedCache 清除相关缓存（仅清除当前操作相关的缓存）
func (t *TableOperator) ClearRelatedCache(conditions map[string]interface{}) error {
	if t == nil || t.client == nil || t.client.cache == nil {
		return nil
	}

	// 如果有自定义缓存键，直接删除它
	if t.cacheKey != "" {
		t.client.cache.Del(t.cacheKey)
		return nil
	}

	// 对于自动生成的缓存键，不自动清除，让其自然过期
	// 这样避免误删除其他条件的缓存
	// 如果需要强制清除，可以调用 ClearCache() 方法

	return nil
}

// ClearAllCache 清除所有缓存
func (t *TableOperator) ClearAllCache() error {
	if t == nil || t.client == nil || t.client.cache == nil {
		return nil
	}

	return t.client.cache.Clear()
}
